home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume25 / newmail < prev    next >
Encoding:
Text File  |  1991-12-19  |  14.7 KB  |  554 lines

  1. Newsgroups: comp.sources.unix
  2. From: creps@silver.ucs.indiana.edu (Steve Creps)
  3. Subject: v25i073: newmail - utility to check for new mail
  4. Sender: sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: creps@silver.ucs.indiana.edu (Steve Creps)
  8. Posting-Number: Volume 25, Issue 73
  9. Archive-Name: newmail
  10.  
  11.    This is a program I wrote a couple of years ago to check for
  12. new mail.  I originally wrote it so that I could type a quick
  13. command to check my mail without actually going into mail, but
  14. recently added an option to let it run in the background.
  15.  
  16.    This was first written on a VAX running Ultrix, but most of the
  17. recent changes were done under HP-UX.  I did, however, try it out
  18. and lint it again under Ultrix.  Send me any bug reports.  I hope
  19. this will be the last version, but if not, I hope it's the next-to-
  20. last version, the last being a bugfix.
  21.  
  22.     Steve Creps
  23.     creps@silver.ucs.indiana.edu (129.79.1.6)
  24.     {inuxc,rutgers,uunet!uiucdcs,pur-ee}!iuvax!silver!creps
  25.  
  26. #! /bin/sh
  27. # This is a shell archive.  Remove anything before this line, then unpack
  28. # it by saving it into a file and typing "sh file".  To overwrite existing
  29. # files, type "sh file -c".  You can also feed this as standard input via
  30. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  31. # will see the following message at the end:
  32. #        "End of archive 1 (of 1)."
  33. # Contents:  BSD.man Makefile README SYSV.man killnewmail.BSD
  34. #   killnewmail.SYSV newmail.c newmail.man
  35. # Wrapped by creps@silver on Fri Jul 19 18:52:20 1991
  36. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  37. if test -f 'BSD.man' -a "${1}" != "-c" ; then 
  38.   echo shar: Will not clobber existing file \"'BSD.man'\"
  39. else
  40. echo shar: Extracting \"'BSD.man'\" \(29 characters\)
  41. sed "s/^X//" >'BSD.man' <<'END_OF_FILE'
  42. X.ds MB /usr/spool/mail/$USER
  43. END_OF_FILE
  44. if test 29 -ne `wc -c <'BSD.man'`; then
  45.     echo shar: \"'BSD.man'\" unpacked with wrong size!
  46. fi
  47. # end of 'BSD.man'
  48. fi
  49. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  50.   echo shar: Will not clobber existing file \"'Makefile'\"
  51. else
  52. echo shar: Extracting \"'Makefile'\" \(954 characters\)
  53. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  54. X# Makefile for newmail(1), Steve Creps, July 17, 1991.
  55. X#LOC=/usr/contrib
  56. XLOC=/usr2/creps
  57. XBIN=$(LOC)/bin
  58. XMAN=$(LOC)/man/man1.Z
  59. X#
  60. X# Define for BSD, Ultrix, etc.
  61. XSYSTEM=BSD
  62. X# Define for SYS V, HP-UX, etc.
  63. X#SYSTEM=SYSV
  64. X#
  65. XOWNER=creps
  66. XCFLAGS=-O -s -D$(SYSTEM)
  67. XLINTFLAGS=-D$(SYSTEM)
  68. XKILLFILES=killnewmail.SYSV killnewmail.BSD
  69. XMANFILES=newmail.man BSD.man SYSV.man
  70. XFILES=newmail.c $(MANFILES) $(KILLFILES) README Makefile
  71. X
  72. Xnewmail: newmail.c
  73. X    cc $(CFLAGS) -o newmail newmail.c
  74. X
  75. Xnewmail.1: newmail.man $(SYSTEM).man
  76. X    cat $(SYSTEM).man newmail.man >newmail.1
  77. X
  78. Xkillnewmail: killnewmail.$(SYSTEM)
  79. X    cp killnewmail.$(SYSTEM) killnewmail
  80. X
  81. Xinstall: newmail newmail.1 killnewmail
  82. X    chmod 0555 newmail killnewmail
  83. X    chmod 0444 newmail.1
  84. X    chown $(OWNER) newmail newmail.1 killnewmail
  85. X    mv newmail killnewmail $(BIN)
  86. X    compress newmail.1
  87. X    mv newmail.1.Z $(MAN)/newmail.1
  88. X
  89. Xtar:    newmail.tar
  90. X
  91. Xnewmail.tar: $(FILES)
  92. X    tar cvf newmail.tar $(FILES)
  93. X
  94. Xlint:
  95. X    lint $(LINTFLAGS) newmail.c
  96. END_OF_FILE
  97. if test 954 -ne `wc -c <'Makefile'`; then
  98.     echo shar: \"'Makefile'\" unpacked with wrong size!
  99. fi
  100. # end of 'Makefile'
  101. fi
  102. if test -f 'README' -a "${1}" != "-c" ; then 
  103.   echo shar: Will not clobber existing file \"'README'\"
  104. else
  105. echo shar: Extracting \"'README'\" \(495 characters\)
  106. sed "s/^X//" >'README' <<'END_OF_FILE'
  107. XNewmail, version 3.0, Steve Creps, July 19, 1991.
  108. XGive information on existence of new mail messages.  See the man
  109. Xpage file (newmail.man) for information on the program.
  110. X
  111. XThis program has been tested under Ultrix and HP-UX.
  112. X
  113. XPrevious versions had no version numbers, only dates, so 3.0 is
  114. Xa somewhat arbitrary version number.
  115. X
  116. XChanges from previous version to version 3.0:
  117. X
  118. X- Rewrote command line parsing code to use getopt(3).
  119. X
  120. X- Added -i option and killnewmail script (daemon mode handling).
  121. END_OF_FILE
  122. if test 495 -ne `wc -c <'README'`; then
  123.     echo shar: \"'README'\" unpacked with wrong size!
  124. fi
  125. # end of 'README'
  126. fi
  127. if test -f 'SYSV.man' -a "${1}" != "-c" ; then 
  128.   echo shar: Will not clobber existing file \"'SYSV.man'\"
  129. else
  130. echo shar: Extracting \"'SYSV.man'\" \(26 characters\)
  131. sed "s/^X//" >'SYSV.man' <<'END_OF_FILE'
  132. X.ds MB /usr/mail/$LOGNAME
  133. END_OF_FILE
  134. if test 26 -ne `wc -c <'SYSV.man'`; then
  135.     echo shar: \"'SYSV.man'\" unpacked with wrong size!
  136. fi
  137. # end of 'SYSV.man'
  138. fi
  139. if test -f 'killnewmail.BSD' -a "${1}" != "-c" ; then 
  140.   echo shar: Will not clobber existing file \"'killnewmail.BSD'\"
  141. else
  142. echo shar: Extracting \"'killnewmail.BSD'\" \(92 characters\)
  143. sed "s/^X//" >'killnewmail.BSD' <<'END_OF_FILE'
  144. X#!/bin/sh
  145. Xkill `ps -fg | fgrep newmail | fgrep -e -d | fgrep -v fgrep | awk '{ print $1 }'`
  146. END_OF_FILE
  147. if test 92 -ne `wc -c <'killnewmail.BSD'`; then
  148.     echo shar: \"'killnewmail.BSD'\" unpacked with wrong size!
  149. fi
  150. # end of 'killnewmail.BSD'
  151. fi
  152. if test -f 'killnewmail.SYSV' -a "${1}" != "-c" ; then 
  153.   echo shar: Will not clobber existing file \"'killnewmail.SYSV'\"
  154. else
  155. echo shar: Extracting \"'killnewmail.SYSV'\" \(101 characters\)
  156. sed "s/^X//" >'killnewmail.SYSV' <<'END_OF_FILE'
  157. X#!/bin/sh
  158. Xkill `ps -fu $LOGNAME | fgrep newmail | fgrep -e -d | fgrep -v fgrep | awk '{ print $2 }'`
  159. END_OF_FILE
  160. if test 101 -ne `wc -c <'killnewmail.SYSV'`; then
  161.     echo shar: \"'killnewmail.SYSV'\" unpacked with wrong size!
  162. fi
  163. # end of 'killnewmail.SYSV'
  164. fi
  165. if test -f 'newmail.c' -a "${1}" != "-c" ; then 
  166.   echo shar: Will not clobber existing file \"'newmail.c'\"
  167. else
  168. echo shar: Extracting \"'newmail.c'\" \(5561 characters\)
  169. sed "s/^X//" >'newmail.c' <<'END_OF_FILE'
  170. X/* newmail(1L), check for new, unread, and total mail messages */
  171. X/* Steve Creps, October 24, 1988 */
  172. X/* Last modified, July 19, 1991 */
  173. X
  174. X/****************************************************************/
  175. X/* #include standard copyright notice:                */
  176. X/* This program copyright Steve Creps on the above date. Do    */
  177. X/* pretty much what you want with it; HOWEVER:            */
  178. X/*    1) Don't accept any money for it.            */
  179. X/*    2) Do leave my notices intact.                */
  180. X/*    3) Do document your changes before passing it on.    */
  181. X/****************************************************************/
  182. X
  183. X#ifndef lint
  184. Xstatic char ID[] = "Newmail, version 3.0, (c) 1991 Steve Creps";
  185. X#endif
  186. X
  187. X#include <stdio.h>
  188. X#include <string.h>
  189. X#include <errno.h>
  190. X#include <sys/types.h>
  191. X#include <malloc.h>
  192. X
  193. X#define Fprintf (void)fprintf
  194. X#define Printf (void)printf
  195. X#define NEW 1
  196. X#define UNREAD 2
  197. X#define OLD 3
  198. X#define DEF_INTERVAL    30 /* Default sleep time between checks */
  199. X#define MIN_INTERVAL    5  /* Min must be > 0 */
  200. X#ifdef BSD
  201. X#define MAILDIR "/usr/spool/mail"
  202. X#define ENV_USER "USER"
  203. X#else
  204. X#define MAILDIR "/usr/mail"
  205. X#define ENV_USER "LOGNAME"
  206. X#endif
  207. X
  208. Xint optn = 0, optt = 0, optv = 1, opti = 0, optd = 0;
  209. Xint optb = 0;
  210. Xint ncount, ucount, tcount, old_ncount = -1;
  211. Xint nextmsg(), type;
  212. X
  213. Xchar *getenv(), *getln();
  214. Xint getopt();
  215. Xunsigned int sleep();
  216. Xvoid exit();
  217. Xextern int opterr, optind;
  218. Xextern char *optarg;
  219. Xpid_t fork(), getpid();
  220. X
  221. Xint
  222. Xmain(argc, argv)
  223. Xint argc;
  224. Xchar *argv[];
  225. X{
  226. X    char *mailfile;
  227. X    int c;
  228. X    FILE *mailfp;
  229. X    pid_t child_id = 0;
  230. X
  231. X    opterr = 0;
  232. X    while ((c = getopt(argc, argv, "bdi:nstv")) != EOF) {
  233. X        switch (c) {
  234. X      case 'b':
  235. X        optb = 1;
  236. X        break;
  237. X
  238. X      case 'd':
  239. X        optd = optn = 1;
  240. X        opti = DEF_INTERVAL;
  241. X        break;
  242. X
  243. X      case 'i':
  244. X        if ((opti = atoi(optarg)) < MIN_INTERVAL) {
  245. X        Fprintf(stderr,
  246. X            "newmail: time interval is too small\n");
  247. X        exit(-1);
  248. X        }
  249. X        break;
  250. X
  251. X      case 'n':
  252. X        optn = 1;
  253. X        optt = 0;
  254. X        break;
  255. X
  256. X      case 's':
  257. X        optt = optv = 0;
  258. X        break;
  259. X
  260. X      case 't':
  261. X        optt = 1;
  262. X        optn = optv = 0;
  263. X        break;
  264. X
  265. X      case 'v':
  266. X        optv = 1;
  267. X        optt = 0;
  268. X        break;
  269. X
  270. X      case '?':
  271. X        Fprintf(stderr, "newmail: invalid option: %s\n",
  272. X            argv[optind - 1]);
  273. X        exit(-1);
  274. X    }
  275. X    }
  276. X
  277. X    if (argc > optind + 1) {
  278. X    Fprintf(stderr, "Usage: newmail [ -b -d -i interval -n -s -t -v ] [ mailbox ]\n");
  279. X    exit(-1);
  280. X    }
  281. X
  282. X    if (optd == 0 || (child_id = fork()) == 0) {
  283. X    if (optd && child_id == 0) {
  284. X        Printf("newmail daemon started, pid == %d\n", getpid());
  285. X    }
  286. X
  287. X    if (argc == optind) {
  288. X        char *u = getenv(ENV_USER);
  289. X        mailfile = (char *)malloc(sizeof(MAILDIR) + sizeof("/") +
  290. X                      sizeof(u) + 1);
  291. X        (void)sprintf(mailfile, "%s/%s", MAILDIR, u);
  292. X    } else {
  293. X#ifdef SYSV
  294. X      mailfile = strdup(argv[optind]);
  295. X#else
  296. X      /* No strdup() on Ultrix; sigh.  Don't try to free this below. */
  297. X      mailfile = argv[optind];
  298. X#endif
  299. X    }
  300. X
  301. X    do {
  302. X        ncount = ucount = tcount = 0;
  303. X        if ((mailfp = fopen(mailfile, "r")) == NULL) {
  304. X        if (errno != ENOENT || argc > optind) {
  305. X            Fprintf(stderr, "newmail: cannot open %s\n",
  306. X                mailfile);
  307. X            return -1;
  308. X        }
  309. X        } else {
  310. X        while (type = nextmsg(mailfp)) {
  311. X            switch (type) {
  312. X              case NEW:
  313. X            ncount++;
  314. X
  315. X              case UNREAD:
  316. X            ucount++;
  317. X
  318. X              case OLD:
  319. X            tcount++;
  320. X            break;
  321. X
  322. X              default:
  323. X            continue;
  324. X            }
  325. X        }
  326. X        }
  327. X
  328. X        if (ncount > old_ncount) {
  329. X        if (optv) {
  330. X            if (optb && ncount > 0) putchar(0x07);
  331. X            if (tcount == 0) {
  332. X            if (!optn) Printf("%s: no messages.\n",
  333. X                      mailfile);
  334. X            } else {
  335. X            Printf("%s: ", mailfile);
  336. X            if (ncount) Printf("%d new, ", ncount);
  337. X            if (ucount && ucount != ncount) 
  338. X                Printf("%d unread, ", ucount);
  339. X            Printf("%d message%s total.\n", tcount,
  340. X                   tcount > 1 ? "s" : "");
  341. X            }
  342. X        } else if (optt)
  343. X            Printf("%d\t%d\t%d\n", ncount, ucount, tcount);
  344. X        }
  345. X        old_ncount = ncount;
  346. X        (void)fclose(mailfp);
  347. X#ifdef BSD
  348. X        if (opti > 0) (void)sleep((unsigned)opti);
  349. X#else
  350. X        if (opti > 0) (void)sleep((unsigned long)opti);
  351. X#endif
  352. X    } while (opti > 0);
  353. X    }
  354. X#ifdef SYSV
  355. X    /* Just to be neat.  See comment after strdup() above. */
  356. X    free((void *)mailfile);
  357. X#endif
  358. X
  359. X    return optd > 0 ? child_id : ncount;
  360. X}
  361. X
  362. X#define MAXLEN 12 /* we're discarding most of the end of the line */
  363. Xstatic char line[MAXLEN] = NULL;
  364. X
  365. Xint
  366. Xnextmsg(fp)
  367. XFILE *fp;
  368. X{
  369. X    int mtype = NEW, past_header = 0;
  370. X    while (strncmp(line, "From ", 5) != 0)
  371. X    if (getln(fp, line, MAXLEN) == NULL) return 0;
  372. X    do {
  373. X    if (strlen(line) == 1) {
  374. X        past_header++;
  375. X        while (strlen(line) == 1)
  376. X        (void)getln(fp, line, MAXLEN);
  377. X        if (strncmp(line, "From ", 5) == 0) {
  378. X        return mtype;
  379. X        }
  380. X    }
  381. X    if (strncmp(line, "Status: O", 9) == 0) {
  382. X        if (!past_header) mtype = UNREAD;
  383. X        continue;
  384. X    }
  385. X    if (strncmp(line, "Status: RO", 10) == 0) {
  386. X        if (!past_header) mtype = OLD;
  387. X        continue;
  388. X    }
  389. X    } while (getln(fp, line, MAXLEN));
  390. X
  391. X    return mtype;
  392. X}
  393. X
  394. X/* Read a line from given stream, return in line. If line is too */
  395. X/* long, truncate and read past next \n. Terminate with (char)0. */
  396. Xchar *
  397. Xgetln(fp, msgline, maxlen)
  398. XFILE *fp;
  399. Xchar msgline[];
  400. Xint maxlen;
  401. X{
  402. X    int i, maxc = maxlen - 2;
  403. X    char c;
  404. X    for (i = 0; i < maxc && (msgline[i] = getc(fp)) != '\n'; i++) {
  405. X    if ((int)msgline[i] == EOF) {
  406. X        msgline[0] = (char)0;
  407. X        return NULL;
  408. X    }
  409. X    }
  410. X
  411. X    if (i == maxc) {
  412. X    msgline[maxc++] = '\n';
  413. X    msgline[maxc] = (char)0;
  414. X    while ((c = getc(fp)) != '\n') {
  415. X        if ((int)c == EOF) {
  416. X        msgline[0] = (char)0;
  417. X        return NULL;
  418. X        }
  419. X    }
  420. X    } else {
  421. X    msgline[i++] = '\n';
  422. X    msgline[i] = (char)0;
  423. X    }
  424. X
  425. X    return msgline;
  426. X}
  427. END_OF_FILE
  428. if test 5561 -ne `wc -c <'newmail.c'`; then
  429.     echo shar: \"'newmail.c'\" unpacked with wrong size!
  430. fi
  431. # end of 'newmail.c'
  432. fi
  433. if test -f 'newmail.man' -a "${1}" != "-c" ; then 
  434.   echo shar: Will not clobber existing file \"'newmail.man'\"
  435. else
  436. echo shar: Extracting \"'newmail.man'\" \(2552 characters\)
  437. sed "s/^X//" >'newmail.man' <<'END_OF_FILE'
  438. X.TH NEWMAIL 1L
  439. X.SH NAME
  440. Xnewmail \- display numbers of new, unread, and total mail messages
  441. X.SH SYNTAX
  442. X.B newmail
  443. X[ \fB-b -d -i interval -n -s -t -v\fR ] [ \fBmailbox\fR ]
  444. X
  445. X.B killnewmail
  446. X
  447. X.SH DESCRIPTION
  448. XThe
  449. X.I newmail
  450. Xcommand displays the number of messages in the given \fBmailbox\fR,
  451. Xbroken down by new messages, unread messages, and total (including
  452. Xold) messages.
  453. XIt also returns as a status code the number of new messages in the
  454. Xmailbox.
  455. XIf \fBmailbox\fR is not specified, then it checks the user's default
  456. Xmailbox,
  457. X\*(MB.
  458. X
  459. X.I Killnewmail
  460. Xis a shell script that kills the
  461. X.I newmail
  462. Xdaemon (see the -d option).
  463. X
  464. X.I Newmail
  465. Xaccepts the following flags:
  466. X
  467. X.IP \fB\-b\fP 5
  468. XBeep if the mailbox contains new messages.
  469. X
  470. X.IP \fB\-d\fP 5
  471. XThis option starts
  472. X.I newmail
  473. Xas a daemon which checks the mailbox every
  474. X.B interval
  475. Xseconds.
  476. XIf
  477. X.B interval
  478. Xis not specified, it defaults to 30 seconds.
  479. X
  480. X.IP \fB\-i interval\fP 5
  481. XSpecifies a time interval for a delay between repeated mailbox
  482. Xchecks.
  483. XThis puts the program into an endless loop.
  484. XIf this option is desired, consider also the \fB-d\fR option.
  485. X
  486. X.IP \fB\-n\fP 5
  487. XInhibits an output message if \fBmailbox\fR contains no messages.
  488. X
  489. X.IP \fB\-s\fP 5
  490. XSpecifies silent mode.
  491. XNothing is displayed, but the return status gives the number of
  492. Xmessages.
  493. XOptions \fB-s\fR, \fB-t\fR, and \fB-v\fR are mutually exclusive, and
  494. Xoverride one another.
  495. X
  496. X.IP \fB\-t\fP 5
  497. XSpecifies terse mode.
  498. XThe numbers of messages are displayed in the form "new unread total",
  499. Xsuitable for piping through \fIawk\fR.
  500. X
  501. X.IP \fB\-v\fP 5
  502. XSpecifies verbose mode.
  503. XDisplays the numbers of messages in \fBmailbox\fR in the format
  504. X"\*(MB: x new, y unread, z total messages".\ 
  505. XIf x or y is zero, then the corresponding output field will be
  506. Xomitted.
  507. XDefault.
  508. X.PP
  509. X
  510. X.SH DIAGNOSTICS
  511. XA nonnegative return code specifies the number of new messages in
  512. X\fBmailbox\fR.
  513. XIf the \fB-d\fR option is specified, then the pid of the created
  514. Xdaemon is returned.
  515. XA return code of -1 indicates an error.
  516. X
  517. X.SH CAVEAT
  518. XWhen in a looping mode (\fB-i\fR or \fB-d\fR), \fInewmail\fR can miss
  519. Xmessages that arrive within \fBinterval\fR seconds of reading one's
  520. Xmail (and thus clearing the messages' "new" flags).
  521. XThis is because \fInewmail\fR is interested only in net increases in
  522. Xthe mailbox message count, and it takes that much time before the
  523. Xcount can be assumed to be reset to zero.
  524. X
  525. X.SH AUTHOR
  526. XWritten by Steve Creps, Indiana University, October 24, 1988, based
  527. Xon observation of Unix mailbox format.
  528. XNot derived from anyone else's code.
  529. XLast modified July 19, 1991.
  530. END_OF_FILE
  531. if test 2552 -ne `wc -c <'newmail.man'`; then
  532.     echo shar: \"'newmail.man'\" unpacked with wrong size!
  533. fi
  534. # end of 'newmail.man'
  535. fi
  536. echo shar: End of archive 1 \(of 1\).
  537. cp /dev/null ark1isdone
  538. MISSING=""
  539. for I in 1 ; do
  540.     if test ! -f ark${I}isdone ; then
  541.     MISSING="${MISSING} ${I}"
  542.     fi
  543. done
  544. if test "${MISSING}" = "" ; then
  545.     echo You have the archive.
  546.     rm -f ark[1-9]isdone
  547. else
  548.     echo You still need to unpack the following archives:
  549.     echo "        " ${MISSING}
  550. fi
  551. ##  End of shell archive.
  552. exit 0
  553.  
  554.